import { FontFamily, CtrlType, ClassName, Events } from "../../Constants";
import { IPixelPos, Style } from "../../Interface";
import Rect from "./Rect";
import Feature from "../Feature";
import { Utils } from "../../utils";
import Cursor from "../function-shape/Cursor";
import GridSystem from "@/GridSystem";

interface Span {
    x: number;
    y: number,
    word: string,
    line: number,
}

// 文本元素
class Text extends Rect {

    static inputElement: HTMLInputElement | null;

    editable: boolean = true;
    fitFontSize: boolean = true;  // 形变时文字适应大小
    fitSize: boolean = true; // 编辑时宽高适应大小

    fontWeight: number = 1;
    strokeWidth: number = 0;
    strokeColor: string = 'orange'
    underLine: Style | null = null;
    color: string = "#000";

    _content: string = '测试文本'
    get content() { return this._content }
    set content(val) {
        this._content = val;
        this._rowArr = this.getFormatStr();
    }
    _fontFamily: FontFamily = FontFamily.SHISHANG
    get fontFamily() { return this._fontFamily }
    set fontFamily(val) {
        this._fontFamily = val;
        this.computedSize();
    }
    _fontSize: number = 1
    get fontSize() { return this._fontSize }
    set fontSize(val) {
        this._fontSize = val;
        this.computedSize();
    }

    spanIndex: number = -1;
    _rowArr: string[] = [];  // 当前文本被分成多少行
    _spanArr: Span[] = [];   // 每一行的每一个文字信息
    _lastWidth: number = 0;

    _setCursorPos = () => { }
    _onEdit = (e: any) => { }
    _onBlur = (e: any) => { }
    _onResize = (e: any) => { }

    constructor(text: string = "默认文本", x: number = 0, y: number = 0, fontSize = 12, width?: number, height?: number) {
        super(x, y, width, height);
        this.className = ClassName.TEXT;
        this.content = text;
        this.fontSize = fontSize;
        this.lineHeight = 2;
        this.fontWeight = 0;
        this.strokeStyle = "transparent"
        this.fillStyle = this.hoverStyle = this.focusStyle = "transparent";
        // this.strokeStyle = '#000'
        // this.strokeWidth = .2;
        this.isStroke = true;
        // this._rowArr = this.getFormatStr();
        this.computedSize(width, height);
        this._lastWidth = this.getBboxSize().width;
        this._setCursorPos = () => { this.setCursorPos() }
        this._onEdit = (e: any) => {
            if (Cursor.getInstance().parent == this) return;  // 已经是在编辑了就不执行
            Feature.Gls.on(Events.TRANSLATE, this._setCursorPos)
            Feature.Gls.on(Events.ZOOM, this._setCursorPos)
            this.on(Events.TRANSLATE, this._setCursorPos)
            this.onEdit(e)
        }
        this._onBlur = this.onBlur.bind(this)
        this._onResize = this.onResize.bind(this)
        this.on(Events.RESIZE, this._onResize)
        this.on(Events.DBLCLICK, this._onEdit)
        this.on(Events.BLUR, this._onBlur)
    }

    onResize(e: any) {
        if (e.detail) {
            const ctrlp = e.detail.trigger;
            if (ctrlp) {
                if (this.fitFontSize && ctrlp.type === CtrlType.SIZE_CTRL) {
                    const { width } = this.getBboxSize()
                    this._fontSize = width / this._lastWidth * this._fontSize;   // 根据宽度变化的百分比,同步放大fontSize
                    this._lastWidth = width;
                }
                if (ctrlp.type === CtrlType.WIDTH_CTRL) {
                    this._lastWidth = this.getBboxSize().width;
                    // this._rowArr = this.getFormatStr();
                }
            }
        }
    }

    onBlur() {
        Cursor.getInstance().parent = null;
        if (Text.inputElement) {
            document.body.removeChild(Text.inputElement);
            Text.inputElement = null;
        }
        if (this.content === '') {
            Feature.Gls.removeFeature(this);
        }
        Feature.Gls.off(Events.TRANSLATE, this._setCursorPos)
        Feature.Gls.off(Events.ZOOM, this._setCursorPos)
        this.off(Events.TRANSLATE, this._setCursorPos)
        this.off(Events.BLUR, this._onBlur)
    }

    setCursorPos(index = this.spanIndex) {
        if (index > -1 && this._spanArr[index]) {
            const { x, y } = this._spanArr[index];
            Cursor.getInstance().setPos(x, y);
            this.spanIndex = index;
        }
    }

    onEdit(e: any, index: number = -1) {
        if (GridSystem.isMobile) {
            var txt = prompt("请输入内容", this.content);   // prompt 无法换行,需要开发者用html代码代替
            this.content = txt || '';
            this.dispatch(new CustomEvent(Events.EDIT, { detail: this }))
            this.computedSize()
        } else {
            if (!this.editable) return
            const O = Feature.Gls.getPixelPos(Feature.getCenterPos(this.pointArr));
            const mousePos = Utils.getRotatePnt(O, Utils.getMousePos(Feature.Gls.domElement, e.detail), -this.angle);

            const fontSize = Feature.Render.getRatioSize(Feature.Gls.getRelativeLen(this.fontSize));
            const cursor = Cursor.getInstance();
            cursor.parent = this;
            const DURATION = 15;

            const nearSpan = Utils.getNearestPoint({ x: mousePos.x, y: mousePos.y - fontSize / 2 }, this._spanArr);
            let spanIndex = this._spanArr.findIndex(span => span === nearSpan);
            if (spanIndex < 0) spanIndex = index;
            if (spanIndex > -1) {
                this.setCursorPos(spanIndex);
                cursor.toDel = () => {  // 向后删除
                    this.content = this.content.substring(0, spanIndex) + this.content.substring(spanIndex + 1);
                    this.dispatch(new CustomEvent(Events.EDIT, { detail: this }))
                    this.computedSize();
                    this.setCursorPos(spanIndex);
                }
                cursor.toBackspace = () => {  // 向前删除
                    this.content = this.content.substring(0, spanIndex - 1) + this.content.substring(spanIndex);
                    this.dispatch(new CustomEvent(Events.EDIT, { detail: this }))
                    this.computedSize();
                    spanIndex--;
                    this.setCursorPos(spanIndex);
                }
                cursor.toLeft = () => {  // 光标左移
                    if (spanIndex - 1 < 0) return;
                    spanIndex--;
                    this.setCursorPos(spanIndex);
                }
                cursor.toRight = () => { // 光标右移
                    if (spanIndex + 1 > this._spanArr.length - 1) return;
                    spanIndex++;
                    this.setCursorPos(spanIndex);
                }
                cursor.toUp = () => { // 光标上移
                    const span = this._spanArr[spanIndex];
                    if (span.line - 1 < 0) return
                    const prevNearSpan = Utils.getNearestPoint({ x: span.x, y: span.y - fontSize * 1.2 }, this._spanArr.filter(sp => sp.line === span.line - 1));
                    let prevSpanIndex = this._spanArr.findIndex(span => span === prevNearSpan);
                    this.setCursorPos(prevSpanIndex);
                    spanIndex = prevSpanIndex;
                }
                cursor.toDown = () => {  // 光标下移
                    const span = this._spanArr[spanIndex];
                    if (span.line + 1 > this._rowArr.length - 1) return;
                    const nextNearSpan = Utils.getNearestPoint({ x: span.x, y: span.y + fontSize * 1.2 }, this._spanArr.filter(sp => sp.line === span.line + 1));
                    let nextSpanIndex = this._spanArr.findIndex(span => span === nextNearSpan);
                    this.setCursorPos(nextSpanIndex);
                    spanIndex = nextSpanIndex;
                }
                cursor.toEnter = () => { // 回车换行
                    this.content = this.content.slice(0, spanIndex) + "\n" + this.content.slice(spanIndex);
                    this.computedSize();
                    setTimeout(() => {
                        spanIndex++;
                        this.setCursorPos(spanIndex);
                        this.dispatch(new CustomEvent(Events.EDIT, { detail: this }))
                    }, DURATION);
                }
            }

            if (Text.inputElement) {
                document.body.removeChild(Text.inputElement)
            }
            const input = Text.inputElement = document.createElement("input");
            input.style.border = "1px solid";
            input.style.position = "fixed";
            input.style.zIndex = "-1";
            input.style.opacity = "0";
            input.style.left = mousePos.x + "px";
            input.style.top = mousePos.y + "px";
            document.body.appendChild(input)

            setTimeout(() => { input.focus() }, 30);
            let lastInputType = ''
            input.addEventListener("input", (ev) => {
                const e = ev as InputEvent;
                lastInputType = e.inputType;
                if (e.inputType === 'insertText') {
                    this.content = this.content.slice(0, spanIndex) + input.value + this.content.slice(spanIndex);
                    input.value = ''
                    this.computedSize();
                    setTimeout(() => {
                        spanIndex++;
                        this.setCursorPos(spanIndex);
                        this.dispatch(new CustomEvent(Events.EDIT, { detail: this }))
                    }, DURATION);
                }
            })
            window.addEventListener("keydown", (e) => {
                if (lastInputType === 'insertCompositionText' && e.code === 'Space' || e.code === 'Enter') {
                    setTimeout(() => {
                        const len = input.value.length;
                        this.content = this.content.slice(0, spanIndex) + input.value + this.content.slice(spanIndex);
                        input.value = ''
                        this.computedSize();
                        setTimeout(() => {
                            spanIndex += len;
                            this.setCursorPos(spanIndex);
                            this.dispatch(new CustomEvent(Events.EDIT, { detail: this }))
                        }, DURATION + 5);
                    }, 25);
                }
            })
        }
    }

    // 获取一行一行的文本数组中,最长的那一行
    getMaxWidth(rowArr: string[] = [], fontSize = 0) {
        let maxLen = 0
        const offscreenCanvas = document.createElement('canvas');
        const ctx = offscreenCanvas.getContext('2d') as CanvasRenderingContext2D;
        ctx.font = `${this.bolder ? 'bolder' : ''} ${fontSize}px ${this.fontFamily}`;
        rowArr.forEach(t => {
            if (ctx.measureText(t).width > maxLen) maxLen = ctx.measureText(t).width;
        })
        return maxLen;
    }

    // 重新计算并设置text的宽高
    computedSize(width?: number, height?: number) {
        if (!this.fitSize) return;
        const rowArr = this.content.split("\n");
        if (width == undefined) {
            const txtWidth = this.getMaxWidth(rowArr, this.fontSize);
            width = txtWidth
        }
        if (height == undefined) {
            const lineHeight = Feature.Render.getPixelLen(this.lineHeight);
            height = this.fontSize * rowArr.length + lineHeight * (rowArr.length - 1);
        }
        this._lastWidth = width;
        this.setSize(width, height);
        this.dispatch(new CustomEvent(Events.CHANGE, { detail: { target: this } }));
    }

    // 将文本打散成一行一行的,根据\n符
    getFormatStr() {
        const offscreenCanvas = document.createElement('canvas');
        // 获取离屏Canvas的2D渲染上下文  
        const ctx = offscreenCanvas.getContext('2d') as CanvasRenderingContext2D;
        ctx.font = `${this.bolder ? 'bolder' : ''} ${this.fontSize}px ${this.fontFamily}`;
        let lastSubstrIndex = 0; //每次开始截取的字符串的索引
        // let contentWidth = 0;
        const rowArr = [];
        for (let i = 0; i < this.content.length; i++) {
            // const fontWidth = ctx.measureText(this.content[i]).width;
            if (this.content[i] === '\n') {
                const row = this.content.substring(lastSubstrIndex, i + 1);
                rowArr.push(row);
                // contentWidth = 0;
                // contentWidth += fontWidth;
                lastSubstrIndex = i + 1;
                continue;
            }
            // if ((contentWidth + fontWidth) > (boxWidth)) {
            //     // console.log(111);
            //     const txt = this.content.substring(lastSubstrIndex, i);
            //     rowArr.push(txt);
            //     lastSubstrIndex = i;
            //     contentWidth = 0;
            //     contentWidth += fontWidth;
            //     continue;
            // }
            // contentWidth += fontWidth;
        }
        const txt = this.content.substring(lastSubstrIndex);  // 最后一段
        rowArr.push(txt);
        return rowArr;
    }

    override draw(ctx: CanvasRenderingContext2D, pointArr: IPixelPos[], lineWidth: number, lineDashArr: number[]) {
        const path = super.draw(ctx, pointArr, lineWidth, lineDashArr);
        const { leftTop } = this.getBboxSize(pointArr);
        ctx.save();
        if (path) ctx.clip(path);   // 放在旋转前面
        this.rotateCtx(ctx, Feature.getCenterPos(pointArr));
        ctx.textBaseline = "top";
        ctx.fillStyle = this.color;
        const fontSize = Feature.Render.getRatioSize(Feature.Render.getRelativeLen(this.fontSize));
        const lineHeight = Feature.Render.getRatioSize(this.lineHeight);
        ctx.font = `${this.bolder ? 'bolder' : ''} ${fontSize}px ${this.fontFamily}`;
        let contentHeight = 0;
        let contentWidth = 0;

        this._spanArr = [];  // 每一个文字的信息,坐标宽高
        for (let i = 0; i < this._rowArr.length; i++) {
            const row = this._rowArr[i];
            contentWidth = 0;
            row.split("").forEach(word => {
                this._spanArr.push({
                    word,
                    x: leftTop.x + contentWidth,
                    y: leftTop.y + contentHeight,
                    line: i,
                })
                contentWidth += ctx.measureText(word).width;
            });
            contentHeight += (fontSize + lineHeight);
            const fontY = leftTop.y + i * (fontSize + lineHeight);
            if (this.strokeWidth && this.strokeColor) {  // 文字描边
                ctx.strokeStyle = this.strokeColor;
                ctx.lineWidth = Feature.Gls.getRatioSize(this.strokeWidth);
                ctx.strokeText(row, leftTop.x, fontY);
            }
            ctx.fillText(row, leftTop.x, fontY);  // 文字填充
            if (this.underLine) {
                ctx.beginPath();
                ctx.moveTo(leftTop.x, fontY + fontSize)
                ctx.lineTo(leftTop.x + contentWidth, fontY + fontSize)
                ctx.strokeStyle = this.underLine.color || '';
                ctx.lineWidth = this.underLine.lineWidth || 2;
                ctx.stroke();
            }

        }
        this._spanArr.push({
            word: "",
            x: leftTop.x + contentWidth,
            y: leftTop.y + contentHeight - fontSize,
            line: this._rowArr.length - 1,
        })
        ctx.restore();
        return path;
    }

    // override getSvg(pointArr: IPixelPos[] = [], lineWidth: number = 1) {
    //     const offscreenCanvas = document.createElement('canvas');
    //     // 获取离屏Canvas的2D渲染上下文  
    //     const ctx = offscreenCanvas.getContext('2d') as CanvasRenderingContext2D;

    //     const padding = Feature.Render.getRatioSize(this.padding);
    //     const lineHeight = Feature.Render.getRatioSize(this.lineHeight);

    //     const center = Feature.getCenterPos(pointArr);
    //     const { leftTop } = this.getBboxSize(pointArr);
    //     const svgStr = super.getSvg(pointArr, lineWidth);
    //     const fontSize = Feature.Render.getRatioSize(this.fontSize)

    //     let rowArr = ''

    //     ctx.font = `${this.bolder ? 'bolder' : ''} ${fontSize}px ${this.fontFamily}`;

    //     // 文本的起始坐标
    //     const startX = leftTop.x + lineWidth / 2;
    //     const startY = leftTop.y + lineWidth / 2 + lineHeight;

    //     for (let i = 0; i < this._rowArr.length; i++) {  // 去换行
    //         rowArr += `<text x="${startX}" y="${startY + i * (fontSize + lineHeight)}" dominant-baseline="hanging" style="fill:${this.color}; font-family: '${this.fontFamily}'; font-size: ${fontSize}; font-weight:${this.bolder ? 'bolder' : ''};"
    //             >${this._rowArr[i]}</text>`
    //     }
    //     const id = Utils.getUuid();
    //     return svgStr + `
    //     <g clip-path="url(#${id})">
    //         <g transform="translate(${center.x} ${center.y}) rotate(${this.angle}) translate(-${center.x} -${center.y})" opacity="${this.opacity}">
    //             ${rowArr} 
    //         </g>
    //     </g>
    //     <defs>
    //         <clipPath id="${id}" clipPathUnits="userSpaceOnUse">
    //             ${svgStr}
    //         </clipPath>
    //     </defs>
    //     `
    // }

    destroy(): void {
        this.onBlur();
        this.off(Events.RESIZE, this._onResize)
        this.off(Events.DBLCLICK, this._onEdit)
        this.off(Events.BLUR, this._onBlur)
    }
}

export default Text;